package com.test45_JUC;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.*;

/**
 * 线程池
 */
public class Demo25_ThreadPool {

    public static void main(String[] args) throws Exception {
        // test1();
        // test2();
        // test3();
        // test4();
        // test5();
        test6();
    }

    /**
     * newCachedThreadPool，无限大小线程池
     * 所谓的无限大小的线程池，指的是如果发现线程池之中的线程数量不足了，那么就会自动创建一个新的线程，而后将这个新创建的线程保存在线程池之中，
     * 由于这种操作会无限制的增长，如果超过了其允许的线程个数，则也会出现有性能瓶颈，这种操作只是提供了一个线程的统一管理。
     */
    public static void test1() {
        ExecutorService service = Executors.newCachedThreadPool();
        for (int x = 0; x < 5; x++) {
            service.submit(() -> {
                System.out.printf("【%s】沐言科技：www.yootk.com%n", Thread.currentThread().getName());
            });
        }
    }

    /**
     * newFixedThreadPool，固定大小线程池
     */
    public static void test2() {
        // 按照正常的设计，固定大小线程池一定要与硬件有关，而常见的做法就是：内核线程的数量*2
        int core = Runtime.getRuntime().availableProcessors();  // 内核线程数量
        System.err.println("当前服务器的线程数量：" + core);
        ExecutorService service = Executors.newFixedThreadPool(core * 2);
        for (int x = 0; x < 50; x++) {
            service.submit(() -> {
                System.out.printf("【%s】沐言科技：www.yootk.com%n", Thread.currentThread().getName());
            });
        }
    }

    /**
     * newSingleThreadExecutor，单线程池
     * 面试题：请问单线程池有什么作用？能否使用一个线程代替？
     * 如果在没有任何突发情况的环境下，单个线程的确可以代替单线程池，但是之所以去使用单线程池本质上来讲是有一个前提：
     * 线程池可以自动维护单线程，如果你的线程池之中的单线程已经由于某些原因导致中断了，线程池会自动的进行一个单线程的恢复，
     * 可是如果只是一个普通的线程呢，你需要自己来控制。
     */
    public static void test3() {
        ExecutorService service = Executors.newSingleThreadExecutor();
        for (int x = 0; x < 5; x++) {
            service.submit(() -> {
                System.out.printf("【%s】沐言科技：www.yootk.com%n", Thread.currentThread().getName());
            });
        }
    }

    /**
     * newScheduledThreadPool，调度线程池
     */
    public static void test4() {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(6);
        for (int x = 0; x < 5; x++) {
            service.schedule(() -> {
                System.out.printf("【%s】沐言科技：www.yootk.com%n", Thread.currentThread().getName());
            }, 5, TimeUnit.SECONDS);    // 5秒后开始执行此任务
        }
    }

    /**
     * 实现间隔调度处理
     */
    public static void test5() {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(6);
        for (int x = 0; x < 5; x++) {
            service.scheduleAtFixedRate(() -> {
                System.out.printf("【%s】沐言科技：www.yootk.com%n", Thread.currentThread().getName());
            }, 5, 2, TimeUnit.SECONDS);    // 5秒后开始执行此任务，每隔2秒再执行一次
        }
    }

    /**
     * Callable实现线程池的调度
     */
    public static void test6() throws Exception {
        ExecutorService service = Executors.newFixedThreadPool(2);
        // 在集合里面存放所有要执行的线程的任务对象，而这个任务对象为CallabLe实现
        Set<Callable<String>> allThreads = new HashSet<>();
        for (int x = 0; x < 5; x++) {
            final int temp = x;
            allThreads.add(() -> {
                return String.format("【%s】YOOTK任务的处理结果：num = %d",
                        Thread.currentThread().getName(), temp);
            });  // 加入线程集合
        }
        // 执行任务
        List<Future<String>> results = service.invokeAll(allThreads);
        results.forEach(future -> {
            try {
                System.out.println(future.get());
            } catch (Exception e) {}
        });
    }
}
